#pragma once

#include "mp3types.h"
#include "BitStream.h"

enum e_version { MPEG2_LSF, MPEG1 };
enum e_mode { stereo, joint_stereo, dual_channel, single_channel };
enum e_sample_frequency { fourtyfour_point_one, fourtyeight, thirtytwo };

class CMP3Header
{
	e_version h_version;
	e_mode h_mode;
	e_sample_frequency	h_sample_frequency;

	static const uint32	frequencies[2][4];

	uint32 h_layer, h_protection_bit, h_bitrate_index, h_padding_bit, h_mode_extension;
	uint32 h_number_of_subbands, h_intensity_stereo_bound;

	bool h_copyright, h_original;
	bool initial_sync;

	uint32 *offset;
	uint16 checksum;
	uint32 framesize;
	uint32 nSlots;

public:
	CMP3Header() : framesize(0), nSlots(0), offset(0), initial_sync(false) {};
	~CMP3Header() { delete [] offset; };

	// read a 32-bit header from the bitstream
	bool read_header(CBitStream *stream);

	// functions to query header contents:
	e_version version() const { return h_version; }
	uint32 layer() const { return h_layer; }
	uint32 bitrate_index() const { return h_bitrate_index; }

	e_sample_frequency sample_frequency() const { return h_sample_frequency; }
	uint32 frequency() const { return frequencies[h_version][h_sample_frequency]; }

	e_mode mode() const { return h_mode; }
	bool checksums() const { return (h_protection_bit == 0); }
	bool copyright() const { return h_copyright; }
	bool original() const { return h_original; }

	// compares computed checksum with stream checksum
	bool checksum_ok () const { return true; }

	// Seeking and layer III stuff
	bool padding() const { return (h_padding_bit != 0); }
	uint32 slots() const { return nSlots; }
	uint32 mode_extension() const { return h_mode_extension; }
	uint32 calculate_framesize();

	// returns the number of subbands in the current frame
	uint32 number_of_subbands() const { return h_number_of_subbands; }

	// (Layer II joint stereo only)
	// returns the number of subbands which are in stereo mode,
	// subbands above that limit are in intensity stereo mode
	uint32 intensity_stereo_bound() const { return h_intensity_stereo_bound; }

	// Scrolling stuff
	uint32 max_number_of_frames(CBitStream *stream) const;
	uint32 min_number_of_frames(CBitStream *stream) const;

	// milliseconds per frame, for time display
	real ms_per_frame() const;
	real total_ms(CBitStream *stream) const { return ((real)max_number_of_frames(stream)*ms_per_frame()); };
};

// Returns the maximum number of frames in the stream
inline uint32 CMP3Header::max_number_of_frames(CBitStream *stream) const
{
	return(stream->file_size() / (framesize + 4 - h_padding_bit));
};

// Returns the minimum number of frames in the stream
inline uint32 CMP3Header::min_number_of_frames(CBitStream *stream) const
{
	return(stream->file_size() / (framesize + 5 - h_padding_bit));
};

static real ms_per_frame_array[3][3] = { {8.707483f,8.0f,12.0f}, {26.12245f, 24.0f, 36.0f}, {26.12245f, 24.0f, 36.0f} };
inline real CMP3Header::ms_per_frame() const
{
	return ms_per_frame_array[h_layer-1][h_sample_frequency];
};
